package org.bluedream.comm.base;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.shiro.SecurityUtils;
import org.bluedream.comm.fill.GoalFieldFill;
import org.bluedream.comm.utils.EmptyUtil;
import org.bluedream.comm.utils.ReflexUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Collection;
import java.util.List;
import java.util.Map;

@Transactional(
        readOnly = true
)
public class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M , T> {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    @Transactional(
            readOnly = false,
            rollbackFor = Exception.class
    )
    public boolean save(T entity) {
        GoalFieldFill<T> fill = new GoalFieldFill<>();
        String loginInfo = (String) SecurityUtils.getSubject().getPrincipal();
        ReflexUtil.setFieldValue(entity , "updateBy" , loginInfo);
        try {
            boolean isNewRecord = fill.getIsNewRecord(entity);
            if (isNewRecord){
                fill.fillInsert(entity);
                ReflexUtil.setFieldValue(entity , "createBy" , loginInfo);
            }else {
                return updateById(entity);
            }
        }catch (Exception e1){
            e1.printStackTrace();
            logger.error(e1.getMessage());
            //todo:@Transactional和try catch捕获异常会让注解失效
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
        return super.save(entity);
    }

    @Override
    @Transactional(
            readOnly = false,
            rollbackFor = Exception.class
    )
    public boolean updateById(T entity) {
        GoalFieldFill<T> fill = new GoalFieldFill<>();
        try {
            boolean isNewRecord = fill.getIsNewRecord(entity);
            if (!isNewRecord){
                fill.fillUpdate(entity);
            }
        }catch (Exception e1){
            e1.printStackTrace();
            logger.error(e1.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return false;
        }
        return super.updateById(entity);
    }

    /**
     * 封装findPage
     * @param entity
     * @param search  Map中的key：";"为保留关键字，拆分数组，仅支持最大长度2的数组，
     *                下标0：QueryWrapper查询条件中的列名(支持多表关联查询的表别名 + 列名方式，需要dao层接口支持)
     *                下标1： QueryWrapper中不同的查询条件，eq：等于，ge：大于等..... todo：请自行完善Mybatis eq、ne、gt、lt、ge、le等
     *                Map中的value：QueryWrapper需要查询的值
     * @param args  QueryWrapper中order by 排序数组
     * @return
     */
    public IPage<T> findPage(T entity , Map<String , Object> search , String... args){
        long current = 1L;
        long size = 10L;
        if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "page")) && (long) ReflexUtil.getFieldValue(entity , "page") != 0){
            current = (long) ReflexUtil.getFieldValue(entity , "page");
        }
        if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "limit")) && (long) ReflexUtil.getFieldValue(entity , "limit") != 0){
            size = (long) ReflexUtil.getFieldValue(entity , "limit");
        }

        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("1" , "1");
        if (EmptyUtil.isNoEmpty(search)){
            for (Map.Entry<String , Object> entry:search.entrySet()
                 ) {
                String[] key = entry.getKey().split(";");
                if (key.length > 1){
                    if (key[1].equals("eq")){
                        queryWrapper.eq(key[0] , entry.getValue());
                    }else if (key[1].equals("ge")){
                        queryWrapper.ge(key[0] , entry.getValue());
                    }else if (key[1].equals("lt")){
                        queryWrapper.lt(key[0] , entry.getValue());
                    }
                }else {
                    queryWrapper.like(entry.getKey() , entry.getValue());
                }
            }
        }
        queryWrapper.orderByAsc(args);
        return super.page(new Page<T>(current , size) , queryWrapper);
    }

    public IPage<T> findPage(T entity , QueryWrapper<T> queryWrapper){
        long current = 1L;
        long size = 10L;
        if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "page")) && (long) ReflexUtil.getFieldValue(entity , "page") != 0){
            current = (long) ReflexUtil.getFieldValue(entity , "page");
        }
        if (EmptyUtil.isNoEmpty(ReflexUtil.getFieldValue(entity , "limit")) && (long) ReflexUtil.getFieldValue(entity , "limit") != 0){
            size = (long) ReflexUtil.getFieldValue(entity , "limit");
        }
        return super.page(new Page<T>(current , size) , queryWrapper);
    }

    public boolean getIsNewRecord(T entity , Map<String , String> searchMap){
        try {
            QueryWrapper<T> qw = new QueryWrapper<>();
            qw.eq("status" , "0");
            for (Map.Entry<String , String> m:searchMap.entrySet()
                 ) {
                Object searchValue = ReflexUtil.invoke(entity , m.getValue() , null);
                qw.eq(m.getKey() , searchValue);
            }
            List<T> list = super.list(qw);
            return EmptyUtil.isEmpty(list)?true:false;
        }catch (Exception e){
            logger.error("获取isNewRecord属性失败，错误信息：" + e.getMessage() + "，POJO = " + entity.getClass());
            return false;
        }
    }

    public T getOne(T entity , Map<String , String> searchMap){
        try {
            QueryWrapper<T> qw = new QueryWrapper<>();
            qw.eq("status" , "0");
            for (Map.Entry<String , String> m:searchMap.entrySet()
            ) {
                Object searchValue = ReflexUtil.invoke(entity , m.getValue() , null);
                qw.eq(m.getKey() , searchValue);
            }
            return super.getOne(qw);
        }catch (Exception e){
            logger.error("getOne is error,error message:" + e.getMessage() + "，POJO = " + entity.getClass());
        }
        return null;
    }

    public void setIsNewRecord(T entity , Map<String , String> searchMap){
        Class<?>[] clazz = {boolean.class};
        ReflexUtil.invoke(entity , "setOrgCode" , clazz , getIsNewRecord(entity , searchMap));
    }

    public boolean getIsNewRecord(T entity , String search, String searchMethodName){
        try {
            Object searchValue = ReflexUtil.invoke(entity , searchMethodName , null);
//                    CustomReflexUtil.getMethodValue(entity , searchMethodName);
            QueryWrapper<T> qw = new QueryWrapper<>();
            qw.eq(search , searchValue);
            List<T> list = super.list(qw);
            if (EmptyUtil.isEmpty(list)){
                return true;
            }else {
                return false;
            }
        }catch (Exception e){
            logger.error("获取isNewRecord属性失败，错误信息：" + e.getMessage() + "，POJO = " + entity.getClass());
            return false;
        }
    }

    /**
     * 1. 判断 传入的对象是否与集合中的某个对象相等
     * 2. 如果相等时，删除来源集合中对应的元素，并返回true，否则返回false
     * @param arg0
     * @param arg1
     * @return
     */
    public boolean obj2EqualsRemoveObj(T arg0 , List<T> arg1){
        for (T var0:arg1
             ) {
            if (arg0.equals(var0)){
                arg1.remove(var0);
                return true;
            }
        }
        return false;
    }

    public List<T> getListBySearch(T arg0 , String searchStr , Object search){
        QueryWrapper<T> oldQw = new QueryWrapper<>();
        oldQw.eq(searchStr , search);
        return list(oldQw);
    }

    @Override
    @Transactional(
            readOnly = false,
            rollbackFor = Exception.class
    )
    public boolean saveBatch(Collection<T> entityList) {
        try {
            for (T var0:entityList
                 ) {
                this.save(var0);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e.getMessage());
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return false;
    }
}
